/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ejb.cliente;

import applicationexcepcion.OrdineException;
import applicationexcepcion.OrdineQuantitaException;
import common.ProdottoQuantita;
import common.StatoOrdine;
import ejb.common.ClienteManagerLocal;
import ejb.common.DettaglioOrdineManagerLocal;
import ejb.common.FornituraManagerLocal;
import ejb.common.NegozioManagerLocal;
import ejb.common.OrdineManagerLocal;
import ejb.common.ProdottoManagerLocal;
import entity.DettaglioOrdine;
import entity.DettaglioPrezzo;
import entity.Fornitura;
import entity.Negozio;
import entity.Ordine;
import entity.Prodotto;
import entity.SpeseSpedizione;
import java.io.Serializable;
import static java.lang.Math.ceil;
import java.sql.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

/**
 *
 * @author Valerio
 */
@Stateful
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class CarrelloEJB implements CarrelloEJBLocal, Serializable {

    private static final long serialVersionUID = 5646234185641203230L;
    @EJB
    private ClienteManagerLocal clienteManager;
    @EJB
    private DettaglioOrdineManagerLocal dettaglioOrdineManager;
    @EJB
    private ProdottoManagerLocal prodottoManager;
    @EJB
    private OrdineManagerLocal ordineManager;
    @EJB
    private FornituraManagerLocal fornituraManager;
    //variabili di instanza private     
    private Map<Long, ProdottoQuantita> carrello;
    private Float subTotale;

    @PreDestroy
    protected void preDestroy() {
        svuotaCarrello();
    }

    @PostConstruct
    protected void init() {
        this.carrello = new HashMap<Long, ProdottoQuantita>();
        this.subTotale = new Float(0.00);
    }

    @Override
    public void aggiungiProdottoAlCarrello(final Long idProdotto, final Long idNegozio, final Integer quantita) throws OrdineQuantitaException {
        controlloProdotto(idProdotto, idNegozio);
        ProdottoQuantita pq;
        if ((pq = carrello.get(idProdotto)) != null) {
            controlloQuantita(idProdotto, idNegozio, pq.getQuantità() + quantita);
            rimuoviDalSubTotale(pq, idNegozio);
            int tmp = pq.getQuantità() + quantita;
            pq.setQuantità(tmp);
            aggiungiAlSubTotale(pq, idNegozio);
            return;
        }
        controlloQuantita(idProdotto, idNegozio, quantita);
        pq = new ProdottoQuantita(idProdotto, quantita);
        aggiungiAlSubTotale(pq, idNegozio);
        this.carrello.put(idProdotto, pq);
    }

    @Override
    public void rimuoviProdottoDalCarrello(Long idProdotto, Long idNegozio) {
        ProdottoQuantita pq;
        if ((pq = carrello.get(idProdotto)) == null) {
            throw new IllegalArgumentException();
        }
        rimuoviDalSubTotale(pq, idNegozio);
        carrello.remove(idProdotto);
    }

    @Override
    public void rimuoviQuantitaDalCarrello(Long idProdotto, Integer quantita, Long idNegozio) {
        if (quantita <= 0) {
            throw new IllegalArgumentException();
        }
        ProdottoQuantita pq;
        if ((pq = carrello.get(idProdotto)) == null) {
            throw new IllegalArgumentException();
        }
        int tmp = pq.getQuantità() - quantita;
        if (tmp < 0) {
            throw new IllegalArgumentException();
        } else if (tmp == 0) {
            carrello.remove(idProdotto);
            rimuoviDalSubTotale(pq, idNegozio);
        } else {
            rimuoviDalSubTotale(new ProdottoQuantita(idProdotto, pq.getQuantità() - tmp), idNegozio);
            pq.setQuantità(tmp);
        }
    }

    @Override
    public List<Prodotto> getProdotti() {
        return prodottoManager.prodottiDaUnSet(carrello.keySet());
    }

    @Override
    public Integer getQuantitaProdotto(Long idProdotto) {
        ProdottoQuantita pq;
        if ((pq = carrello.get(idProdotto)) == null) {
            throw new IllegalArgumentException();
        }
        return pq.getQuantità();
    }

    @Override
    public Integer getQuantitaProdotto(Prodotto prodotto) {
        return this.getQuantitaProdotto(prodotto.getCodiceBarre());
    }

    @Override
    public Float getSubTotale() {
        return subTotale;
    }

    @Override
    public Float getTotale(SpeseSpedizione spese) {
        return subTotale + spese.getPrezzo();
    }

    /**
     * Processa ordine prende il carrello corrente. Se non è disponibile la
     * quantità di un prodotto lancia OrdineException.
     *
     * @param idCliente
     * @param spese
     * @throws OrdineException
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void processaOrdine(Long idCliente, SpeseSpedizione spese) throws OrdineException {
        if (idCliente == null || spese == null) {
            throw new IllegalArgumentException("Parametri scorretti");
        }
        if (carrello.isEmpty()) {
            throw new IllegalStateException("Carrello vuoto o non è stato aggiunto un nuovo prodotto");
        }
        //prendo il negozio dalla spesa
        Negozio n = spese.getAddetto().getNegozio();
        //crea la lista di dettaglio ordine
        //creazione ordine
        Ordine o = new Ordine();
        o.setCliente(clienteManager.cercaClientePerId(idCliente));
        o.setDataOrdine(new Date(new GregorianCalendar().getTimeInMillis()));
        o.setNegozio(n);
        o.setStato(StatoOrdine.in_Elaborazione);
        o.setTotale(subTotale + spese.getPrezzo());
        ordineManager.creaOrdine(o);
        //fine creazione ordine
        for (Long idProdotto : carrello.keySet()) {
            //prendo la fornitura del negozio
            Fornitura f = fornituraManager.cercaFornituraNegozio(idProdotto, n.getId());
            if (f.getQuantita() < carrello.get(idProdotto).getQuantità()) {//se la quantità disponibile è minore della quantità che si vuole aggiungere si lancia un eccezione
                //setto come messaggio dell'exception l'id del prodotto che ha causato l'eccezione
                throw new OrdineException(idProdotto.toString());
            }
            //creo il dettaglioOrdine
            DettaglioOrdine dettaglioOrdine = new DettaglioOrdine();
            f.setQuantita(f.getQuantita() - carrello.get(idProdotto).getQuantità());
            dettaglioOrdine.setOrdine(o);
            dettaglioOrdine.setProdotto(prodottoManager.cercaPerId(idProdotto));
            dettaglioOrdine.setQuantità(carrello.get(idProdotto).getQuantità());
            dettaglioOrdineManager.creaDettaglioOrdine(dettaglioOrdine);
            fornituraManager.modificaFornitura(f);
        }
        svuotaCarrello();
    }

    @Override
    public void svuotaCarrello() {
        this.carrello.clear();
        this.subTotale = new Float(0.00);
    }

    @Override
    public boolean isEmpty() {
        return this.carrello.isEmpty();
    }

    private void controlloProdotto(Long idProdotto, Long idNegozio) {
        boolean controllo = prodottoManager.prodottoFornito(idProdotto, idNegozio);
        if (!controllo) {
            throw new IllegalArgumentException();
        }
    }

    private void controlloQuantita(Long idProdotto, Long idNegozio, Integer quantita) throws OrdineQuantitaException {
        Fornitura f = fornituraManager.cercaFornituraNegozio(idProdotto, idNegozio);
        if (f.getQuantita() < quantita) {
            throw new OrdineQuantitaException("Quantità non disponibiile nel negozio");
        }
    }

    private void aggiungiAlSubTotale(ProdottoQuantita pq, Long idNegozio) {
        DettaglioPrezzo dp = prodottoManager.getPrezzoProdotto(idNegozio, pq.getIdProdotto());
        Float tmp = dp.getPrezzo() * pq.getQuantità();
        this.subTotale += tmp;
        this.subTotale = arrotonda(subTotale);
    }

    private Float arrotonda(Float f) {
        Float tmp = f * 100;
        tmp = (float) ceil(tmp);
        return new Float(tmp / 100);
    }

    private void rimuoviDalSubTotale(ProdottoQuantita pq, Long idNegozio) {
        DettaglioPrezzo dp = prodottoManager.getPrezzoProdotto(idNegozio, pq.getIdProdotto());
        Float tmp = dp.getPrezzo() * pq.getQuantità();
        this.subTotale -= tmp;
        this.subTotale = arrotonda(subTotale);
    }
//    private void bloccaDisponibita(Long idProdotto, Long idNegozio, Integer quantita) {
//        DettaglioOrdine dettaglioOrdine;
//        Fornitura f = fornituraManager.cercaFornituraNegozio(idProdotto, idNegozio);
//        if ((dettaglioOrdine = dettaglioOrdineManager.cercaDettaglioiOrdine(idOrdineCorrente, idProdotto)) != null) {
//            //TODO
//            Integer tmp = f.getQuantita() + dettaglioOrdine.getQuantità();
//            f.setQuantita(tmp - quantita);
//            dettaglioOrdine.setQuantità(quantita);
//            dettaglioOrdineManager.creaDettaglioOrdine(dettaglioOrdine);
//            fornituraManager.modificaFornitura(f);
//            return;
//        }
//        dettaglioOrdine = new DettaglioOrdine();
//        dettaglioOrdine.setOrdine(ordineManager.cercaPerId(idOrdineCorrente));
//        dettaglioOrdine.setProdotto(prodottoManager.cercaPerId(idProdotto));
//        dettaglioOrdine.setQuantità(quantita);
//        f.setQuantita(f.getQuantita() - quantita);
//        dettaglioOrdineManager.creaDettaglioOrdine(dettaglioOrdine);
//        fornituraManager.modificaFornitura(f);
//    }
//    private void rilasciaDisponibilita(Long idProdotto, Long idNegozio, Integer quantita) {
//        DettaglioOrdine dettaglioOrdine = dettaglioOrdineManager.cercaDettaglioiOrdine(idOrdineCorrente, idProdotto);
//        Fornitura f = fornituraManager.cercaFornituraNegozio(idProdotto, idNegozio);
//        Integer tmp = dettaglioOrdine.getQuantità() - quantita;
//        if (tmp < 0) {
//            throw new IllegalArgumentException("che cazzo di argomento passi");
//        }
//        f.setQuantita(f.getQuantita() + quantita);
//        dettaglioOrdine.setQuantità(tmp);
//        fornituraManager.modificaFornitura(f);
//        if (dettaglioOrdine.getQuantità() == 0) {
//            dettaglioOrdineManager.eliminaDettaglioOrdine(dettaglioOrdine);
//        } else {
//            dettaglioOrdineManager.modificaDettaglioOrdine(dettaglioOrdine);
//        }
//    }
//    private void rimuoviOrdine() {
//        ordineManager.rimuoviOrdineDaId(idOrdineCorrente);
//        idOrdineCorrente = null;
//    }
}
